package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Qualifier("com.atguigu.tingshu.user.client.UserInfoFeignClient")
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {
        return vodService.uploadTrack(file);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {

        TrackInfoServiceImpl proxyObject = (TrackInfoServiceImpl) AopContext.currentProxy();

        // 1.保存声音基本信息
        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setUserId(AuthContextHolder.getUserId());

        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);  // 声音默认审核通过


        // 1.1 处理声音的orderNum（这个声音在当前专辑中的序列号）
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId());
        wrapper.orderByDesc(TrackInfo::getOrderNum);
        wrapper.last("limit 1");
        TrackInfo trackInfo1 = trackInfoMapper.selectOne(wrapper);
        Integer orderNum = trackInfo1 == null ? 1 : trackInfo1.getOrderNum() + 1;
        trackInfo.setOrderNum(orderNum);

        // 1.2 处理声音的媒体信息
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        if (trackMediaInfoVo == null) {
            throw new GuiguException(201, "该声音对应的媒体信息不存在!");
        }
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
        int insert = trackInfoMapper.insert(trackInfo);
        log.info("保存声音基本信息：{}", insert > 0 ? "success" : "fail");

        // 2.保存声音的统计信息
        Integer integer = proxyObject.saveTrackStat(trackInfo.getId());
        log.info("保存声音统计信息：{}", integer > 0 ? "success" : "fail");


        // 3.反向更新专辑的包含声音集数属性
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "该声音对应的专辑不存在");
        }
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        int i = albumInfoMapper.updateById(albumInfo);
        log.info("更新对应专辑：{}", i > 0 ? "success" : "fail");

    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(IPage<TrackListVo> pageParam, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(pageParam, trackInfoQuery);
    }

    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {


        // 修改声音基本信息表
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new GuiguException(201, "该声音不存在");
        }

        String mediaFileIdNew = trackInfoVo.getMediaFileId();
        if (StringUtils.isEmpty(mediaFileIdNew)) {
            throw new GuiguException(201, "修改的声音源信息不存在");
        }
        String mediaFileIdOld = trackInfo.getMediaFileId();

        BeanUtils.copyProperties(trackInfoVo, trackInfo);

        if (!StringUtils.isEmpty(mediaFileIdNew) && !mediaFileIdNew.equals(mediaFileIdOld)) {
            // 修改声音的时候 重新上传了一个新声音
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(mediaFileIdNew);
            if (trackMediaInfoVo == null) {
                throw new GuiguException(201, "上传的新声音不存在");
            }
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
        }
        trackInfoMapper.updateById(trackInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long trackId) {

        // 1.修改该声音对应专辑的声音集数
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new GuiguException(201, "该声音已经不存在");
        }
        Long albumId = trackInfo.getAlbumId();

        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "该声音对应的专辑不存在");
        }
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);

        // 2.删除声音基本信息
        trackInfoMapper.deleteById(trackId);

        // 3.删除声音统计信息
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));

        // 4.删除vod中的声音（磁盘中临时目录的文件删掉）

        vodService.removeMediaFile(trackInfo.getMediaFileId());

    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> albumTrackListVoPage, Long albumId) {
        IPage<AlbumTrackListVo> result = new Page<AlbumTrackListVo>();

        //查询专辑
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "该专辑不存在");
        }
        //查询声音列表
        albumTrackListVoPage = trackInfoMapper.getAlbumTrackListByAlbumIdFromDb(albumTrackListVoPage, albumId);
        //查询付费信息
        String payType = albumInfo.getPayType();
        String priceType = albumInfo.getPriceType();
        Integer tracksForFree = albumInfo.getTracksForFree();
        Long userId = AuthContextHolder.getUserId();

        result = switch (payType) {
            case "0101" -> albumTrackListVoPage;
            case "0102" -> dealAlbumPayTypeVip(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
            case "0103" -> dealAlbumPayTypeNeedPay(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
            default -> result;
        };
        return result;
    }

    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackStatMapper.getTrackStatVo(trackId);
    }

    @Override
    public List<TrackListVo> getTrackListByIds(List<Long> trackIdList) {
        List<TrackInfo> trackInfos = trackInfoMapper.selectBatchIds(trackIdList);

        return trackInfos.stream().map(trackInfo -> {
            TrackListVo trackListVo = new TrackListVo();
            BeanUtils.copyProperties(trackInfo, trackListVo);
            trackListVo.setTrackId(trackInfo.getId());
            return trackListVo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long currentTrackId) {
        //返回的结果集
        List<Map<String, Object>> result = new ArrayList<>();

        //通过ThreadLocal拿到登录的userId
        Long userId = AuthContextHolder.getUserId();

        //查询声音对象是否存在
        TrackInfo trackInfo = trackInfoMapper.selectById(currentTrackId);
        if (trackInfo == null) {
            throw new GuiguException(201, "当前声音不存在");
        }

        //查询专辑是否存在
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "当前声音对应专辑不存在");
        }

        //查询价格
        BigDecimal price = albumInfo.getPrice();

        //获取声音的序列号
        Integer orderNum = trackInfo.getOrderNum();

        //查询当前声音的后50集(最多一次购买50集)
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TrackInfo::getAlbumId, albumId)
                .gt(TrackInfo::getOrderNum, orderNum)
                .last("limit 50")
                .orderByAsc(TrackInfo::getOrderNum);
        List<TrackInfo> trackInfos = trackInfoMapper.selectList(wrapper);

        //获取用户购买过的声音
        Result<Map<Long, String>> userPaidAlbumTrack = userInfoFeignClient.getUserPaidAlbumTrack(userId, albumId);
        Map<Long, String> userPaidAlbumTrackData = userPaidAlbumTrack.getData();
        if (userPaidAlbumTrackData == null) {
            throw new GuiguException(201, "远程调用用户微服务获取用户购买过的声音失败");
        }

        //过滤已经买过的声音
        List<TrackInfo> reallyShowTrackList = trackInfos.stream().filter(
                trackInfo1 -> !StringUtils.hasText(userPaidAlbumTrackData.get(trackInfo1.getId()))
        ).toList();     //.collect(Collectors.toList())使用于java8 toList()适用于java16之后

        //展示本集
        Map<String, Object> currentMap = new HashMap<>();
        currentMap.put("name", "本集");
        currentMap.put("price", price);
        currentMap.put("trackCount", 0);
        result.add(currentMap);

        //展示后n集 10 20 30
        int size = reallyShowTrackList.size();  //总需要买的集数
        int block = size % 10 == 0 ? size / 10 : size / 10 + 1;
        for (int i = 1; i <= block; i++) {
            int blockSize = i * 10;
            if (blockSize >= size) {
                Map<String, Object> lastMap = new HashMap<>();
                lastMap.put("name", "后" + size + "集");
                lastMap.put("price", price.multiply(new BigDecimal(size)));
                lastMap.put("trackCount", size);
                result.add(lastMap);
                break;
            }
            Map<String, Object> otherMap = new HashMap<>();
            otherMap.put("name", "后" + blockSize + "集");
            otherMap.put("price", price.multiply(new BigDecimal(blockSize)));
            otherMap.put("trackCount", blockSize);
            result.add(otherMap);
        }
        return result;
    }

    @Override
    public List<TrackInfo> getTrackListByCurrentTrackId(Long userId, Long trackId, Integer trackCount) {
        List<TrackInfo> result = new ArrayList<>();

        // 判断声音对象
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new GuiguException(201, "该声音不存在");
        }

        // 2查询该声音对应的专辑id
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "该声音对应的专辑不存在");
        }

        // 判断当前买的声音是本集还是其它集
        if (trackCount == 0) {
            // 本集
            result.add(trackInfo);
        } else {
            // 其它集
            LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(TrackInfo::getAlbumId, albumId);
            wrapper.gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
            wrapper.last("limit " + trackCount);
            wrapper.orderByAsc(TrackInfo::getOrderNum);
            result = trackInfoMapper.selectList(wrapper);
        }

        return result;
    }

    private IPage<AlbumTrackListVo> dealAlbumPayTypeNeedPay(Long albumId, Long userId, String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListVoPage) {
        // 1.判断用户id是否存在
        if (userId == null) {
            List<AlbumTrackListVo> albumTrackListVoList = albumTrackListVoPage.getRecords()
                    .stream()
                    .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= 5)
                    .collect(Collectors.toList());
            return albumTrackListVoPage.setRecords(albumTrackListVoList);
        }
        // 2.用户登录了
        return getReallyShowAlbumTrackList(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
    }

    private IPage<AlbumTrackListVo> dealAlbumPayTypeVip(Long albumId, Long userId, String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListVoPage) {
        if (userId == null) {
            // 展示5集免费的声音返回给前端
            List<AlbumTrackListVo> albumTrackListVoList = albumTrackListVoPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= 5).collect(Collectors.toList());
            return albumTrackListVoPage.setRecords(albumTrackListVoList);
        }
        Result<UserInfoVo> userInfo = userInfoFeignClient.getUserInfo(userId);
        UserInfoVo userInfoData = userInfo.getData();
        if (userInfoData == null) {
            throw new GuiguException(201, "该用户信息不存在");
        }
        Integer isVip = userInfoData.getIsVip();
        Date vipExpireTime = userInfoData.getVipExpireTime();

        if ("0".equals(isVip + "") || ("1".equals(isVip + "") && vipExpireTime.before(new Date()))) {
            return getReallyShowAlbumTrackList(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
        } else {
            return albumTrackListVoPage;
        }
    }

    private IPage<AlbumTrackListVo> getReallyShowAlbumTrackList(Long albumId, Long userId, String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListVoPage) {
        if ("0201".equals(priceType)) {
            Result<Map<Long, String>> userPaidAlbumTrackMap = userInfoFeignClient.getUserPaidAlbumTrack(userId, albumId);
            Map<Long, String> userPaidAlbumTrackMapData = userPaidAlbumTrackMap.getData();
            if (userPaidAlbumTrackMapData == null) {
                throw new GuiguException(201, "远程查询用户微服务获取用户购买过专辑下的声音失败");
            }
            List<AlbumTrackListVo> reallyShowAlbumTrackList = albumTrackListVoPage.getRecords().stream().map(albumTrackListVo -> {
                if (StringUtils.isEmpty(userPaidAlbumTrackMapData.get(albumTrackListVo.getTrackId())) && albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            return albumTrackListVoPage.setRecords(reallyShowAlbumTrackList);
        } else {
            // 3.2 整专辑购买
            Result<Boolean> userPaidAlbum = userInfoFeignClient.getUserPaidAlbum(userId, albumId);
            Boolean isPaidAlbum = userPaidAlbum.getData();
            if (isPaidAlbum == null) {
                throw new GuiguException(201, "远程查询用户微服务获取用户购买过当前专辑失败");
            }
            // 买过该专辑
            if (isPaidAlbum) {
                return albumTrackListVoPage;
            }
            // 没有买过该专辑
            List<AlbumTrackListVo> reallyShowAlbumTrackList = albumTrackListVoPage.getRecords().stream().map(albumTrackListVo -> {
                if (albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());

            return albumTrackListVoPage.setRecords(reallyShowAlbumTrackList);
        }

    }

    @Transactional
    public Integer saveTrackStat(Long trackId) {

        ArrayList<String> trackStatus = new ArrayList<>();
        trackStatus.add(SystemConstant.TRACK_STAT_PLAY);
        trackStatus.add(SystemConstant.TRACK_STAT_COLLECT);
        trackStatus.add(SystemConstant.TRACK_STAT_PRAISE);
        trackStatus.add(SystemConstant.TRACK_STAT_COMMENT);
        try {
            for (String status : trackStatus) {
                TrackStat trackStat = new TrackStat();
                trackStat.setTrackId(trackId);
                trackStat.setStatType(status);
                trackStat.setStatNum(0);
                trackStatMapper.insert(trackStat);
            }
            return 1;
        } catch (Exception e) {
            return 0;
        }
    }
}
